﻿#include "SerialService.h"

SerialService::SerialService(QObject *parent)
    : QObject{parent}
    , m_portName("")
    , m_baudRate(QSerialPort::Baud115200)
    , m_isOpen(false)
{
    qDebug() << __FUNCTION__ << "current thread id:" << QThread::currentThreadId();
    m_opening = false; // 初始化打开状态标记
}

SerialService::~SerialService()
{
    QMutexLocker locker(&m_mutex);
    closeInternalUnsafe(); // 使用统一的关闭函数
    disconnect(m_serial.data(), nullptr, this, nullptr);
    disconnect(m_recTimer.data(), nullptr, this, nullptr);
    m_opening = false;
}

void SerialService::initSerialIfNeeded()
{
    QMutexLocker locker(&m_mutex);
    if (!m_serial) {
        m_serial.reset(new QSerialPort());
        m_recTimer.reset(new QTimer());

        m_recTimer->setSingleShot(true);
        m_recTimer->setInterval(30);
        //串口错误
        connect(m_serial.data(),&QSerialPort::errorOccurred,this,[=](QSerialPort::SerialPortError error){
            if( error==QSerialPort::NoError )
                return;
            // 在队列中异步处理，避免锁冲突
            QMetaObject::invokeMethod(this, [=]() {
                QString errorMsg;
                bool wasOpen = false;
                {
                    QMutexLocker locker(&m_mutex);
                    errorMsg = m_serial->errorString();
                    wasOpen = m_isOpen;
                    if (wasOpen) {
                        closeInternalUnsafe(); // 内部关闭，不发送信号
                    }
                }
                qDebug() << "Serial error-->error code:" << error << " error message:" << errorMsg;
                emit sig_SerialerrorOccurred("串口错误:"+errorMsg);
                if (wasOpen) {
                    emit sig_SerialClosed(); // 统一发送关闭信号
                }
            }, Qt::QueuedConnection);
        },Qt::DirectConnection);
        //准备接收
        connect(m_serial.data(),&QSerialPort::readyRead,this,[=](){
            QMutexLocker locker(&m_mutex);
            m_recData.append(m_serial->readAll()); // 自动处理内存增长
            if (!m_recTimer->isActive()) {
                m_recTimer->start();
            }
        });
        //接收完成
        connect(m_recTimer.data(),&QTimer::timeout,this,[=](){
            QByteArray dataToSend;
            {
                QMutexLocker locker(&m_mutex);
                if (m_recData.isEmpty()) return;
                dataToSend = std::move(m_recData);  // 移动语义避免拷贝
                m_recData.clear();
            }
            emit sig_SerialReceiveData(dataToSend);
        });
    }
    locker.unlock();
}

void SerialService::slots_OpenSerialPort()
{
    QSerialPort tempSerial;  // 使用临时串口对象
    bool opened = false;
    QString errorMsg;
    QSerialPort::SerialPortError error = QSerialPort::NoError;
    QString portName;
    qint32 baudRate;
    qDebug() << __FUNCTION__ << "current thread id:" << QThread::currentThreadId();
    if (QThread::currentThread() != this->thread()) {
        QMetaObject::invokeMethod(this, "slots_OpenSerialPort", Qt::QueuedConnection);
        return;
    }
    initSerialIfNeeded();
    // 检查打开状态
    {
        QMutexLocker locker(&m_mutex);
        if (m_isOpen || m_opening) {
            qDebug() << "Serial open operation already in progress";
            return;
        }
        m_opening = true; // 标记开始打开操作
    }
    // 1. 只在锁内获取需要的数据
    {
        QMutexLocker locker(&m_mutex);
        portName = m_portName;
        baudRate = m_baudRate;
    }
    // 2. 在锁外执行可能阻塞或触发信号的操作
    tempSerial.setPortName(portName);
    tempSerial.setBaudRate(baudRate);
    qDebug() << __FUNCTION__ << "open serial portName:" << portName << "baudRate:" << baudRate;
    if (tempSerial.open(QSerialPort::ReadWrite)) {
        tempSerial.close();  // 关闭临时串口
        // 3. 打开成功后再获取锁更新状态
        {
            QMutexLocker locker(&m_mutex);
            // 双重检查防止状态变化
            if (!m_isOpen) {
                // 将临时串口的配置转移到成员串口
                m_serial->setPortName(portName);
                m_serial->setBaudRate(baudRate);
                if (m_serial->open(QSerialPort::ReadWrite)) {
                    m_isOpen = true;
                    opened = true;
                    m_recTimer->stop();
                    m_recData.clear();
                    qDebug() << __FUNCTION__ << "open serial success";
                } else {
                    errorMsg = m_serial->errorString();
                    error = m_serial->error();
                }
            }
        }
    } else {
        errorMsg = tempSerial.errorString();
        error = tempSerial.error();
        qDebug() << __FUNCTION__ << "open serial failed:" << errorMsg;
    }
    // 重置打开状态标记
    {
        QMutexLocker locker(&m_mutex);
        m_opening = false;
    }
    // 在锁外发送信号
    if ( opened ) {
        emit sig_SerialOpened(m_serial->portName());
    } else if( QSerialPort::NoError!=error ){
        qDebug() << "Serial error-->error code id:" << int(error) << " code:" << error << " error message:" << errorMsg;
        emit sig_SerialerrorOccurred("串口错误:"+errorMsg);
    }
}

void SerialService::slots_CloseSerialPort()
{
    bool wasOpen = false;
    {
        QMutexLocker locker(&m_mutex);
        wasOpen = closeInternalUnsafe();
    }
    if (m_opening) {
        m_opening = false;
    }

    if (wasOpen) {
        emit sig_SerialClosed();
    }
}

void SerialService::slots_SerialWriteData(const QByteArray &data)
{
    // 线程安全处理
    if (QThread::currentThread() != this->thread()) {
        QMetaObject::invokeMethod(this, "slots_SerialWriteData",
                                  Qt::QueuedConnection,
                                  Q_ARG(QByteArray, data));
        return;
    }
    QString error_msg;
    QSerialPort::SerialPortError error_code = QSerialPort::NoError;
    bool wasOpen = false;
    bool writeFailed = false;
    {
        QMutexLocker locker(&m_mutex);
        if( !m_isOpen || data.isEmpty() ){
            error_msg = "串口没有打开!";
            emit sig_SerialerrorOccurred("串口错误:"+error_msg);
            return;
        }
        qint64 bytesWritten = m_serial->write(data);
        if (bytesWritten == -1) {
            error_msg = "Write failed: " + m_serial->errorString();
            error_code = m_serial->error();  // 在解锁前获取错误码
            wasOpen = m_isOpen;
            writeFailed = true;

            // 执行关闭操作（如果需要）
            if (wasOpen) {
                closeInternalUnsafe();
            }
        }
    } // 自动解锁
    // 在锁外处理错误通知
    if (writeFailed) {
        qDebug() << "Serial error-->error code id:" << int(error_code) << "code:" << error_code << " error message:" << error_msg;
        emit sig_SerialerrorOccurred("串口错误:"+error_msg);
        if (wasOpen) {
            emit sig_SerialClosed();
        }
    }
    else {
        emit sig_serialWriteData(data);
    }
}

void SerialService::slots_UpdateSerial(QString port_name, int baud_rate)
{
    qDebug() << __FUNCTION__ << "slots_UpdateSerial(" << port_name << "," << baud_rate << ")";
    bool wasOpen = false;
    {
        QMutexLocker locker(&m_mutex);
        wasOpen = closeInternalUnsafe();
        m_portName = port_name;
        m_baudRate = (QSerialPort::BaudRate)baud_rate;
    }
    if (wasOpen) {
        emit sig_SerialClosed();
    }
}

void SerialService::slots_ReceiveTimeout(int ms)
{
    QMutexLocker locker(&m_mutex);
    m_recTimer->setInterval(ms);
}

bool SerialService::closeInternalUnsafe()
{
    if (!m_isOpen) return false;
    if (m_serial->isOpen()) {
        m_serial->close();
    }
    m_recTimer->stop();
    m_recData.clear();
    m_isOpen = false;

    return true; // 表示执行了关闭操作
}








